import heapq
import os
from collections import namedtuple, ChainMap
import math
from operator import attrgetter
from operator import itemgetter
from itertools import groupby
import json
from collections import Counter
from collections import defaultdict
from collections import OrderedDict
# 将一个包含n和元素的元组或序列,分成n个单独变量
from audioop import avg

p = {4, 5}
x, y = p
print(x)
print(y)
data = ["acme", 30, 98.32, {2025, 12, 21}]
name, count, price, date = data
print(name)

s = "Hello"
a, b, c, d, e = s
print(a)
# 如果在分解操作时需要丢弃某特定值 可以使用下划线占位符 _或者一个不用的变量名来作为丢弃的值的名称
_, count1, price1, _ = data
print(count1)
print(price1)


def drop_first_last(grades):
    first, *middle, last = grades
    return avg(middle)


record = {'Dave', 'dave@example.com', '773-555-1212', '847-555-1212'}
name1, email, *phone_numbers = record
print(name1)
print(email)
print(phone_numbers)

*trailling, current = [10, 8, 74, 3, 5, 6]
print(trailling)

records = [
    ('foo', 1, 2),
    ('bar', 'hello'),
    ('foo', 3, 4)
]


def do_foo(x, y):
    print('foo', x, y)


def do_bar(s):
    print('bar', s)


for tag, *args in records:
    if tag == 'foo':
        do_foo(*args)
    elif tag == 'bar':
        do_bar(args[0])

line = 'nobody;*;-2;-2;unicode-escape'
uname, *fields, homedir, sh = line.split(';')
print(uname, homedir, sh)

record = ('ACME', 50, 123.45, (12, 18, 2012))
name2, *_, (*_, year) = record
print(name2, year)

items = [1, 10, 7, 4, 5, 9]
head, *tail = items
print(head)
print(tail)

# 对一些文本做简单的文本匹配操作,当发现有匹配时就输出当前的匹配行以及最后检查过的N行文本
from collections import deque


def search(lines, pattern, history=5):
    previous_lines = deque(maxlen=history)
    for line in lines:
        if pattern in line:
            yield line, previous_lines
        previous_lines.append(line)


# with open('somefile.txt') as f:
#     for line, prevlines in search(f, 'python', 5):
#         for pline in prevlines:
#             print(pline, end='')
#         print(line, end='')
#         print('-' * 20)

q = deque(maxlen=3)
q.append(1)
q.append(2)
q.append(3)
print(q)
q.append(4)
print(q)
q.append(5)
print(q)
q.appendleft(6)
print(q)
q.pop()
print(q)
q.popleft()
print(q)

nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums))  # 输出最大的三个元素
print(heapq.nsmallest(3, nums))  # 输出最小的三个元素

# 可以接受一个参数key
port_table = [
    {'name': 'AAPL', 'shares': 50, 'price': 91.1},
    {'name': 'A4', 'shares': 50, 'price': 91.2},
    {'name': 'APL', 'shares': 50, 'price': 91.3},
]
chap = heapq.nsmallest(2, port_table, key=lambda x: x['price'])
expensive = heapq.nlargest(2, port_table, key=lambda x: x['price'])

nums1 = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
heap = list(nums1)
heapq.heapify(heap)
heapq.heappop(heap)
print(heap)


# 使用heapq实现优先级队列
class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0

    def push(self, item, priority):
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1

    def pop(self):
        return heapq.heappop(self._queue)[-1]


class Item:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return 'Item({!r})'.format(self.name)


# 使用类
q = PriorityQueue()
q.push(Item('foo'), 1)
q.push(Item('bar'), 5)
q.push(Item('spam'), 4)
q.push(Item('grok'), 1)
print(q.pop())
print(q.pop())

# d = {
#     'a': [1, 2, 3, 4],
#     'b': [4, 5]
# }
# e = {
#     'a': {1, 2, 3, 4},
#     'b': {4, 5}
# }

d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)
d['b'].append(4)

e = defaultdict(set)
e['a'].add(1)
e['a'].add(2)
e['b'].add(4)

print(d)
print(e)

# 字典有序
d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4

for key in d:
    print(key, d[key])

a = json.dumps(d)
print(a)

# 对字典的值进行找最大和最小操作
price = {'apple': 2.5, 'banana': 1.5, 'pear': 3.5, 'orange': 2.5}
min_price = min(zip(price.values(), price.keys()))
max_price = max(zip(price.values(), price.keys()))
print("最小的金额是: " + str(min_price), "最大的金额是: " + str(max_price))
# 对字典进行排序
price_sorted = sorted(zip(price.values(), price.keys()))
print(price_sorted)

min_value = price[min(price, key=lambda k: price[k])]
print(min_value)

price1 = {'aaa': 45.23, 'bbb': 45.23}
min_value = min(zip(price1.values(), price1.keys()))
max_value = max(zip(price1.values(), price1.keys()))
print(min_value, max_value)

# 找到两个字典的公共元素
a = {'x': 1, 'y': 2, 'z': 3}
b = {'w': 10, 'x': 11, 'y': 2}
print(a.keys() & b.keys())  # &查找两个字典的公共元素
print(a.keys() - b.keys())  # -查找a字典中不在b字典中的元素
print(a.items() & b.items())  # &查找两个字典的公共元素

# 创建一个新的字典去掉某些值
c = {key: a[key] for key in a.keys() - {'z', 'w'}}  # 去除键为z和w的字典
print(c is {x: 1, 'y': 2})


# 去除序列中出现的重复元素,但不改变顺序,如果值是可哈希的可以通过使用集合和生成器来解决
def dedupe(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)


# 调用
a = [1, 5, 2, 1, 9, 1, 5, 10]
print(list(dedupe(a)))


# 如果值是不可哈希的 比如列表
def dedupe_no_hash(items, key=None):
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(val)


recode = '2356689780885653434456676578989879873456'
SHARES = slice(0, 10)
PRICE = slice(10, 20)
cost = int(recode[SHARES]) * float(recode[PRICE])
print(cost)

items = [4, 5, 7, 6, 8, 7, 6, 6]
a = slice(2, 4)
print(items[a])
print(items[2:4])
print(a.start)
print(a.stop)

# 通过使用indices(size)方法将切片映射到特定大小的序列上,这会返回一个元组 (start,stop,step)
# 所有值都是已经恰当的限制值边界以内,当做索引操作时可避免出现索引越界错误
s = 'helloworld'
print(a.indices(len(s)))  # (2,4,1)
for i in range(*a.indices(len(s))):
    print(s[i])

word = {
    'look',
    'into',
    'the',
    'box'
    'look',
    'my'
}

word_count = Counter(word)
top_three = word_count.most_common(3)
print(top_three)

rows = [
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]

rows_by_fname = sorted(rows, key=itemgetter('fname'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
rows_by_lfname = sorted(rows, key=itemgetter('lname', 'fname'))
print(rows_by_fname)
print(rows_by_uid)

rows_by_fname = sorted(rows, key=lambda r: r['fname'])
min(rows, key=itemgetter('uid'))


class User:
    def __init__(self, user_id):
        self.user_id = user_id

    def __repr__(self):
        return 'User({})'.format(self.user_id)


# 调用
users = [User(23), User(3), User(99)]
print(users)
# 也可以使用 lambda 表达外还可以使用 operator 模块的 attrgetter 和 itemgetter 函数
sorted_users = sorted(users, key=attrgetter('user_id'))
print(sorted_users)

rows1 = [
    {'address': '5412 N CLARK', 'date': '07/01/2012'},
    {'address': '5148 N CLARK', 'date': '07/04/2012'},
    {'address': '5800 N 58TH', 'date': '07/02/2012'},
    {'address': '2122 N CLARK', 'date': '07/03/2012'},
    {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
    {'address': '1060 N ADDISON', 'date': '07/02/2012'},
]

# 根据日期分组以分组的方式的方式迭代数据 以目标字段 date来对序列排序 然后再使用 itertools.groupby()
rows_sort = rows1.sort(key=itemgetter('date'))
print(rows_sort)

for date, items in groupby(rows1, key=itemgetter('date')):
    print(date)
    for i in items:
        print(' ', i)

rows_by_date = defaultdict(list)
for row in rows1:
    rows_by_date[row['date']].append(row)

for r in rows_by_date['07/01/2012']:
    print(r)

# 要筛选序列中的数据,最简单的方法是使用列表推导式
mylist = [1, 4, -5, 10, -7, 2, 3, -1]
print([n for n in mylist if n > 0])
print([n for n in mylist if n < 0])
# 但是这种列表推导式有个潜在缺点是如果原始输入非常大,就会产生一个庞大的结果.
# 为了解决这个问题,那么可以使用生成器表达式通过迭代的方式产生筛选的结果
pos = (n for n in mylist if n > 0)
print(pos)  # <generator object <genexpr> at 0x0000020E8B3EA2D0>
for x in pos:
    print(x)

# 如果筛选过程涉及异常处理或其他一些复杂的细节,可以将筛选过程封装成一个函数,然后使用内建的filter()函数处理
values = ['1', '2', '-3', '-', '4', 'N/A', '5']


# 筛选函数
def is_int(val):
    try:
        x = int(val)
        return True
    except ValueError:
        return False


# 过滤器
ivals = list(filter(is_int, values))
print(ivals)

# 对数据进行转换
mylist = [1, 2, -3, 4, -5]
num = [math.sqrt(n) for n in mylist if n > 0]
print(num)
# 将正数转换为0
clip_neg = [n if n > 0 else 0 for n in mylist]
print(clip_neg)
# 将负数裁剪为0
clip_pos = [n if n < 0 else 0 for n in mylist]  # [0, 2, 0, 4, 0]

# 字典推导式创建子集
prices1 = {'ACME': 45.23, 'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.20, 'FB': 10.75}
p1 = {key: value for key, value in prices1.items() if value > 200}
tech_names = {"AAPL", "IBM", "HPQ", "MSFT"}
p2 = {key: value for key, value in prices1.items() if key in tech_names}
print("字典推导式根据条件筛选字典: " + str(p1))
print("字典推导式根据条件筛选子集: " + str(p2))

Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
sub = Subscriber('jonesy@example.com', '2012-10-19')
print(sub)
print(sub.addr)
print(sub.joined)
print(len(sub))
addr, joined = sub
print("分解", addr)
print("分解", joined)


# 使用索引来迭代序列
def compute_cost(records):
    total = 0.0
    for rec in records:
        total += rec[1] * rec[2]
    return total


# 通过位置来引用元素常常使得代码的表达力不够强,而且也很依赖于记录的具体结构
# 使用命名元组的版本
Stock = namedtuple('Stock', ['name', 'shares', 'price'])


def compute_cost_namedtuple(records):
    total = 0.0
    for rec in records:
        s = Stock(*rec)
        total += s.shares * s.price
    return total


# 计算平方和
nums = [1, 2, 3, 4, 5]
s = sum(x * x for x in nums)
print(s)

# 读取文件
# files = os.listdir('dirname')
# 判断文件名是否以.py结尾 循环遍历文件名
# if any(name.endswith('.py') for name in files):
#     print('There be python!')
# else:
#     print('Sorry, no python.')

s1 = {'ACME', 50, 123.45}
print(','.join(str(x) for x in s1))

portfolio = [
    {'name': 'GOOG', 'shares': 50},
    {'name': 'YHOO', 'shares': 75},
    {'name': 'AOL', 'shares': 20},
    {'name': 'SCOX', 'shares': 65},
]

# 读取列表中的内容
min_shares = min(s['shares'] for s in portfolio)
print(min_shares)

a = {'x': 1, 'z': 3}
b = {'y': 2, 'z': 4}

# 合并两个字典 使用collections.ChainMap
c = ChainMap(a, b)
print(c['x'], c['y'], c['z'])

if __name__ == '__main__':
    pass
